import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:online_bookstore/models/book.dart';
import 'package:online_bookstore/models/cart_item.dart';
import 'package:online_bookstore/services/storage_service.dart';
import 'package:uuid/uuid.dart';

// Cart State
class CartState {
  final List<CartItem> items;
  final bool isLoading;
  final String? error;

  const CartState({
    this.items = const [],
    this.isLoading = false,
    this.error,
  });

  CartState copyWith({
    List<CartItem>? items,
    bool? isLoading,
    String? error,
  }) {
    return CartState(
      items: items ?? this.items,
      isLoading: isLoading ?? this.isLoading,
      error: error ?? this.error,
    );
  }

  double get totalPrice => items.fold(0, (sum, item) => sum + item.totalPrice);
  int get totalItems => items.fold(0, (sum, item) => sum + item.quantity);
  bool get isEmpty => items.isEmpty;
  bool get isNotEmpty => items.isNotEmpty;

  String get formattedTotalPrice => '\$${totalPrice.toStringAsFixed(2)}';
}

// Cart Notifier
class CartNotifier extends StateNotifier<CartState> {
  final StorageService _storageService;
  final Uuid _uuid = const Uuid();

  CartNotifier(this._storageService) : super(const CartState()) {
    _loadCart();
  }

  Future<void> _loadCart() async {
    state = state.copyWith(isLoading: true);
    try {
      final cartItems = await _storageService.getCart();
      state = state.copyWith(
        items: cartItems,
        isLoading: false,
      );
    } catch (e) {
      state = state.copyWith(
        isLoading: false,
        error: e.toString(),
      );
    }
  }

  Future<void> _saveCart() async {
    try {
      await _storageService.saveCart(state.items);
    } catch (e) {
      state = state.copyWith(error: e.toString());
    }
  }

  Future<void> addToCart(Book book, {int quantity = 1}) async {
    final existingItemIndex = state.items.indexWhere(
      (item) => item.book.id == book.id,
    );

    if (existingItemIndex != -1) {
      // Update existing item
      final existingItem = state.items[existingItemIndex];
      final updatedItem = existingItem.copyWith(
        quantity: existingItem.quantity + quantity,
      );
      
      final updatedItems = List<CartItem>.from(state.items);
      updatedItems[existingItemIndex] = updatedItem;
      
      state = state.copyWith(items: updatedItems);
    } else {
      // Add new item
      final newItem = CartItem(
        id: _uuid.v4(),
        book: book,
        quantity: quantity,
        addedAt: DateTime.now(),
      );
      
      state = state.copyWith(
        items: [...state.items, newItem],
      );
    }

    await _saveCart();
  }

  Future<void> removeFromCart(String cartItemId) async {
    final updatedItems = state.items.where(
      (item) => item.id != cartItemId,
    ).toList();
    
    state = state.copyWith(items: updatedItems);
    await _saveCart();
  }

  Future<void> updateQuantity(String cartItemId, int quantity) async {
    if (quantity <= 0) {
      await removeFromCart(cartItemId);
      return;
    }

    final updatedItems = state.items.map((item) {
      if (item.id == cartItemId) {
        return item.copyWith(quantity: quantity);
      }
      return item;
    }).toList();

    state = state.copyWith(items: updatedItems);
    await _saveCart();
  }

  Future<void> clearCart() async {
    state = const CartState();
    await _storageService.clearCart();
  }

  bool isInCart(String bookId) {
    return state.items.any((item) => item.book.id == bookId);
  }

  int getItemQuantity(String bookId) {
    final item = state.items.firstWhere(
      (item) => item.book.id == bookId,
      orElse: () => throw StateError('Item not found'),
    );
    return item.quantity;
  }

  void clearError() {
    state = state.copyWith(error: null);
  }
}

// Cart Provider
final cartProvider = StateNotifierProvider<CartNotifier, CartState>((ref) {
  final storageService = StorageService();
  return CartNotifier(storageService);
});

// Cart Items Count Provider
final cartItemsCountProvider = Provider<int>((ref) {
  final cartState = ref.watch(cartProvider);
  return cartState.totalItems;
});

// Cart Total Price Provider
final cartTotalPriceProvider = Provider<double>((ref) {
  final cartState = ref.watch(cartProvider);
  return cartState.totalPrice;
});

// Is Book In Cart Provider
final isBookInCartProvider = Provider.family<bool, String>((ref, bookId) {
  final cartNotifier = ref.watch(cartProvider.notifier);
  return cartNotifier.isInCart(bookId);
});

// Book Quantity In Cart Provider
final bookQuantityInCartProvider = Provider.family<int, String>((ref, bookId) {
  final cartNotifier = ref.watch(cartProvider.notifier);
  try {
    return cartNotifier.getItemQuantity(bookId);
  } catch (e) {
    return 0;
  }
});
